2222#include <linux/sysfs.h>
2323#include <linux/timer.h>
2424
25+ #include <linux/map_to_7segment.h>
26+ #include <linux/map_to_14segment.h>
27+
2528#include "line-display.h"
2629
2730#define DEFAULT_SCROLL_RATE (HZ / 2)
@@ -188,19 +191,79 @@ static ssize_t scroll_step_ms_store(struct device *dev,
188191
189192static DEVICE_ATTR_RW (scroll_step_ms );
190193
194+ static ssize_t map_seg_show (struct device * dev , struct device_attribute * attr , char * buf )
195+ {
196+ struct linedisp * linedisp = container_of (dev , struct linedisp , dev );
197+ struct linedisp_map * map = linedisp -> map ;
198+
199+ memcpy (buf , & map -> map , map -> size );
200+ return map -> size ;
201+ }
202+
203+ static ssize_t map_seg_store (struct device * dev , struct device_attribute * attr ,
204+ const char * buf , size_t count )
205+ {
206+ struct linedisp * linedisp = container_of (dev , struct linedisp , dev );
207+ struct linedisp_map * map = linedisp -> map ;
208+
209+ if (count != map -> size )
210+ return - EINVAL ;
211+
212+ memcpy (& map -> map , buf , count );
213+ return count ;
214+ }
215+
216+ static const SEG7_DEFAULT_MAP (initial_map_seg7 );
217+ static DEVICE_ATTR (map_seg7 , 0644 , map_seg_show , map_seg_store ) ;
218+
219+ static const SEG14_DEFAULT_MAP (initial_map_seg14 );
220+ static DEVICE_ATTR (map_seg14 , 0644 , map_seg_show , map_seg_store ) ;
221+
191222static struct attribute * linedisp_attrs [] = {
192223 & dev_attr_message .attr ,
193224 & dev_attr_scroll_step_ms .attr ,
194- NULL ,
225+ & dev_attr_map_seg7 .attr ,
226+ & dev_attr_map_seg14 .attr ,
227+ NULL
228+ };
229+
230+ static umode_t linedisp_attr_is_visible (struct kobject * kobj , struct attribute * attr , int n )
231+ {
232+ struct device * dev = kobj_to_dev (kobj );
233+ struct linedisp * linedisp = container_of (dev , struct linedisp , dev );
234+ struct linedisp_map * map = linedisp -> map ;
235+ umode_t mode = attr -> mode ;
236+
237+ if (attr == & dev_attr_map_seg7 .attr ) {
238+ if (!map )
239+ return 0 ;
240+ if (map -> type != LINEDISP_MAP_SEG7 )
241+ return 0 ;
242+ }
243+
244+ if (attr == & dev_attr_map_seg14 .attr ) {
245+ if (!map )
246+ return 0 ;
247+ if (map -> type != LINEDISP_MAP_SEG14 )
248+ return 0 ;
249+ }
250+
251+ return mode ;
252+ };
253+
254+ static const struct attribute_group linedisp_group = {
255+ .is_visible = linedisp_attr_is_visible ,
256+ .attrs = linedisp_attrs ,
195257};
196- ATTRIBUTE_GROUPS (linedisp );
258+ __ATTRIBUTE_GROUPS (linedisp );
197259
198260static DEFINE_IDA (linedisp_id );
199261
200262static void linedisp_release (struct device * dev )
201263{
202264 struct linedisp * linedisp = container_of (dev , struct linedisp , dev );
203265
266+ kfree (linedisp -> map );
204267 kfree (linedisp -> message );
205268 ida_free (& linedisp_id , linedisp -> id );
206269}
@@ -210,6 +273,44 @@ static const struct device_type linedisp_type = {
210273 .release = linedisp_release ,
211274};
212275
276+ static int linedisp_init_map (struct linedisp * linedisp )
277+ {
278+ struct linedisp_map * map ;
279+ int err ;
280+
281+ if (!linedisp -> ops -> get_map_type )
282+ return 0 ;
283+
284+ err = linedisp -> ops -> get_map_type (linedisp );
285+ if (err < 0 )
286+ return err ;
287+
288+ map = kmalloc (sizeof (* map ), GFP_KERNEL );
289+ if (!map )
290+ return - ENOMEM ;
291+
292+ map -> type = err ;
293+
294+ /* assign initial mapping */
295+ switch (map -> type ) {
296+ case LINEDISP_MAP_SEG7 :
297+ map -> map .seg7 = initial_map_seg7 ;
298+ map -> size = sizeof (map -> map .seg7 );
299+ break ;
300+ case LINEDISP_MAP_SEG14 :
301+ map -> map .seg14 = initial_map_seg14 ;
302+ map -> size = sizeof (map -> map .seg14 );
303+ break ;
304+ default :
305+ kfree (map );
306+ return - EINVAL ;
307+ }
308+
309+ linedisp -> map = map ;
310+
311+ return 0 ;
312+ }
313+
213314/**
214315 * linedisp_register - register a character line display
215316 * @linedisp: pointer to character line display structure
@@ -242,6 +343,11 @@ int linedisp_register(struct linedisp *linedisp, struct device *parent,
242343 device_initialize (& linedisp -> dev );
243344 dev_set_name (& linedisp -> dev , "linedisp.%u" , linedisp -> id );
244345
346+ /* initialise a character mapping, if required */
347+ err = linedisp_init_map (linedisp );
348+ if (err )
349+ goto out_put_device ;
350+
245351 /* initialise a timer for scrolling the message */
246352 timer_setup (& linedisp -> timer , linedisp_scroll , 0 );
247353
@@ -260,6 +366,7 @@ int linedisp_register(struct linedisp *linedisp, struct device *parent,
260366 device_del (& linedisp -> dev );
261367out_del_timer :
262368 del_timer_sync (& linedisp -> timer );
369+ out_put_device :
263370 put_device (& linedisp -> dev );
264371 return err ;
265372}
0 commit comments